package is.client.model;

import is.client.controller.command.ConnectionLostCommand;
import is.common.datatype.Request;
import is.common.exception.DroppingNonEmptyDepartmentException;
import is.common.exception.RowNotFoundException;
import is.common.exception.UniqueCheckFailedException;
import is.common.interfaces.mvc.Model;
import is.common.syntax.CommandQualifier;
import is.common.syntax.TransactionStatus;
import is.common.util.ObjectStreamer;
import is.common.watchdog.WatchdogClientThread;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 * User: aspr0
 * Date: 29.03.12
 * Time: 4:38
 */
public class ClientModel implements Model
{
    private Socket socket;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    private WatchdogClientThread watchdogThread;
    private ObjectStreamer objectStreamer;

    private boolean activated = false;


    public void activate(String server, int port, int controlPort) throws IOException
    {
        socket = new Socket(server, port);

        objectInputStream = new ObjectInputStream(socket.getInputStream());
        objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        objectStreamer = new ObjectStreamer(objectInputStream, objectOutputStream);

        watchdogThread = new WatchdogClientThread(server, controlPort);
        watchdogThread.setConnectionLostCommand(new ConnectionLostCommand());

        watchdogThread.start();

        activated = true;
    }

    public void deactivate() throws IOException
    {
        if (activated)
        {
            objectOutputStream.close();
            objectInputStream.close();
            socket.close();

            watchdogThread.deactivate();

            activated = false;
        }
    }

    @Override
    public boolean isActivated()
    {
        return activated;
    }

    @Override
    public String[] getHeader(Integer sectionNum) throws IOException, ClassNotFoundException
    {
        Request request = new Request(CommandQualifier.LIST_HEADER, sectionNum);
        objectStreamer.transmitObject(request);

        return objectStreamer.receiveStrings();
    }

    @Override
    public String[][] getRows(Integer sectionNum, Integer rowNumStart, Integer howMany)
            throws IOException, ClassNotFoundException
    {
        Request request = new Request(CommandQualifier.LIST_ROWS, sectionNum);
        objectStreamer.transmitObject(request);

        return objectStreamer.receiveStringsDouble();
    }

    @Override
    public void addRow(Integer sectionNum, String[] row)
            throws IOException, ClassNotFoundException, RowNotFoundException, UniqueCheckFailedException
    {
        Request request = new Request(CommandQualifier.ADD, sectionNum, row);
        objectStreamer.transmitObject(request);

        receiveTransactionStatus();
    }

    @Override
    public void editRow(Integer sectionNum, String[] row)
            throws IOException, ClassNotFoundException, UniqueCheckFailedException, RowNotFoundException
    {
        Request request = new Request(CommandQualifier.EDIT, sectionNum, row);
        objectStreamer.transmitObject(request);

        receiveTransactionStatus();
    }

    @Override
    public String dropRows(Integer sectionNum, String[] rowIds)
            throws IOException, ClassNotFoundException, DroppingNonEmptyDepartmentException
    {
        Request request = new Request(CommandQualifier.DROP, sectionNum, rowIds);
        objectStreamer.transmitObject(request);

        String transactionStatus = objectStreamer.receiveString();

        if (transactionStatus.equals(TransactionStatus.TRANSACTION_FAILED_DROPPING_NON_EMPTY_DEPARTMENT))
        {
            throw new DroppingNonEmptyDepartmentException();
        }

        return transactionStatus;
    }

    @Override
    public String[][] findRows(Integer sectionNum, String[] masks) throws IOException, ClassNotFoundException
    {
        Request request = new Request(CommandQualifier.FIND, sectionNum, masks);
        objectStreamer.transmitObject(request);

        return objectStreamer.receiveStringsDouble();
    }


    private void receiveTransactionStatus()
            throws IOException, ClassNotFoundException, RowNotFoundException, UniqueCheckFailedException
    {
        String transactionStatus = objectStreamer.receiveString();

        if (transactionStatus.equals(TransactionStatus.TRANSACTION_FAILED_ROW_NOT_FOUND))
        {
            throw new RowNotFoundException();
        }

        if (transactionStatus.equals(TransactionStatus.TRANSACTION_FAILED_UNIQUE_CHECK))
        {
            throw new UniqueCheckFailedException();
        }

        if (transactionStatus.equals(TransactionStatus.TRANSACTION_OK))
        {
        }
    }
}

